;;;;
;;; Nehe Lesson #20 - Masking
;;; http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=20
;;; XMLisp version by John Miller, millejoh@mac.com, 08/31/09
;;; 

(in-package :xlui)

(use-package :lib.gl)

(defclass masking-view (agent-3d-view)
  ()
  (:documentation "NEHE Lesson 20:Image Masking"))

(defmethod init ((view masking-view))
  (glClearColor 0.0 0.0 0.0 0.0)
  (glClearDepth 1.0d0)
  (glEnable GL_DEPTH_TEST)
  (glShadeModel GL_SMOOTH))

(defmethod use-texture ((self masking-view) texture-name)
  (let* ((Texture-Id (gethash Texture-Name (textures Self))))
    ;; load texture from file if necessary
    (unless Texture-Id
      (setq Texture-Id (create-texture-from-file (texture-file Self Texture-Name) :repeat t))
      (setf (gethash Texture-Name (textures Self)) Texture-Id))
    ;; make the texture active (for now assume a 2D texture
    (when Texture-Id
      (glbindtexture gl_texture_2d Texture-Id))))

(defclass mask-example (agent-3d)
  ((masking-p :accessor masking-p :initarg :masking :initform t)
   (draw-image1-p :accessor draw-image1-p :initarg :draw-image1 :initform nil)
   (image-slide :accessor image-slide :initarg :image-slide :initform 0.0)))

(defmethod draw ((agent mask-example))
  (with-slots (image-slide masking-p draw-image1-p) agent
    (let ((v0 {-1.1 -1.1 0.0})
          (v1 {1.1 -1.1 0.0})
          (v2 {1.1 1.1 0.0})
          (v3 {-1.1 1.1 0.0}))
      (glEnable GL_TEXTURE_2D)
      (use-texture agent "Logo.bmp")
      (with-gl GL_QUADS
        (glTexCoord2f 0.0 (- image-slide))   (glVertex3fv v0)
        (glTexCoord2f 3.0 (- image-slide))   (glVertex3fv v1)
        (glTexCoord2f 3.0 (- 3 image-slide)) (glVertex3fv v2)
        (glTexCoord2f 0.0 (- 3 image-slide)) (glVertex3fv v3))
      ;; Now on to the blending
      (glEnable GL_BLEND)
      (glDisable GL_DEPTH_TEST)
      (if masking-p
        (glBlendFunc GL_DST_COLOR GL_ZERO))
      (if draw-image1-p
        (progn
          (glTranslatef 0.0 0.0 -1.0)
          (glRotatef (* image-slide 360) 0.0 0.0 1.0)
          (when masking-p
            (use-texture agent "Mask2.bmp")
            (with-gl GL_QUADS
              (glTexCoord2f 0.0 0.0) (glVertex3fv v0)
              (glTexCoord2f 1.0 0.0) (glVertex3fv v1)
              (glTexCoord2f 1.0 1.0) (glVertex3fv v2)
              (glTexCoord2f 0.0 1.0) (glVertex3fv v3)))
          (glBlendFunc GL_ONE GL_ONE)
          (use-texture agent "Image2.bmp")
          (with-gl GL_QUADS
            (glTexCoord2f 0.0 0.0) (glVertex3fv v0)
            (glTexCoord2f 1.0 0.0) (glVertex3fv v1)
            (glTexCoord2f 1.0 1.0) (glVertex3fv v2)
            (glTexCoord2f 0.0 1.0) (glVertex3fv v3)))
        (progn
          (when masking-p
            (use-texture agent "Mask1.bmp")
            (with-gl GL_QUADS
              (glTexCoord2f image-slide 0.0)         (glVertex3fv v0)
              (glTexCoord2f (+ 4.0 image-slide) 0.0) (glVertex3fv v1)
              (glTexCoord2f (+ 4.0 image-slide) 4.0) (glVertex3fv v2)
              (glTexCoord2f image-slide 4.0)         (glVertex3fv v3)))
          (glBlendFunc GL_ONE GL_ONE)
          (use-texture agent "Image1.bmp")
          (with-gl GL_QUADS
            (glTexCoord2f image-slide 0.0)         (glVertex3fv v0)
            (glTexCoord2f (+ 4.0 image-slide) 0.0) (glVertex3fv v1)
            (glTexCoord2f (+ 4.0 image-slide) 4.0) (glVertex3fv v2)
            (glTexCoord2f image-slide 4.0)         (glVertex3fv v3))))
      (glEnable GL_DEPTH_TEST)
      (glDisable GL_BLEND))))

(defmethod toggle-masking ((w application-window) _)
  (declare (ignore _))
  (setf (masking-p (first (agents (view-named *masking-example* "Masking Example"))))
        (not (masking-p (first (agents (view-named *masking-example* "Masking Example")))))))

(defmethod toggle-scene ((w application-window) _)
  (declare (ignore _))
  (setf (draw-image1-p (first (agents (view-named *masking-example* "Masking Example"))))
        (not (draw-image1-p (first (agents (view-named *masking-example* "Masking Example")))))))
  
(defmethod animate ((agent mask-example) dt)
  (incf (image-slide agent) (/ dt 10.0))
  (when (> (image-slide agent) 1.0)
    (setf (image-slide agent) 0.0)))

(defparameter *masking-example* nil)
(defun nehe-lesson-20 ()
  (setq *masking-example*
        (slui (:application-window 
               :title "Nehe Lesson 20, Masking" :margin "0"
               (:masking-view 
                :name "Masking Example" :vflex"1"
                (:camera :eye-z "5.0")
                (:mask-example))))))
        
        


;; 0 = logo, 1 = mask1, 2=image1, 3=mask2, 4=image2.
    
